/*
  +----------------------------------------------------------------------+
  | PHP Version 5                                                        |
  +----------------------------------------------------------------------+
  | Copyright (c) 1997-2010 The PHP Group                                |
  +----------------------------------------------------------------------+
  | This source file is subject to version 3.01 of the PHP license,      |
  | that is bundled with this package in the file LICENSE, and is        |
  | available through the world-wide-web at the following url:           |
  | http://www.php.net/license/3_01.txt                                  |
  | If you did not receive a copy of the PHP license and are unable to   |
  | obtain it through the world-wide-web, please send a note to          |
  | license@php.net so we can mail you a copy immediately.               |
  +----------------------------------------------------------------------+
  | Author: David Soria Parra <david.soria_parra@mayflower.de>           |
  +----------------------------------------------------------------------+
*/

/* $Id:  $ */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"
#include "mysqlnd_uh.h"
#include "mysqlnd_uh_classes.h"
#include "php_mysqlnd_uh.h"

/* resources */
int le_mysqlnd_uh_mysqlnd;
int le_mysqlnd_uh_mysqlnd_res;
int le_mysqlnd_uh_mysqlnd_stmt;


/* MySQLnd plugin related */
struct st_mysqlnd_conn_methods org_mysqlnd_conn_methods;

/* PHP Infrastructure */

/* {{{ mysqlnd_uh_call_method
 Only returns the returned zval if retval_ptr != NULL */
 /*
	A dirty hack for calling methods from C, copied from zend_interfaces.h/zend_interfaces.c.
	Unfortunately the Zend version accepts at most two parameters. But we got a couple more.
	KLUDGE: If Zend ever makes any changes to it, this copy must be updated accordingly.
*/
zval* mysqlnd_uh_call_method(zval **object_pp, zend_class_entry *obj_ce, zend_function **fn_proxy, char *function_name, int function_name_len, zval **retval_ptr_ptr, int param_count, zval* arg1, zval* arg2, zval* arg3, zval* arg4, zval* arg5, zval* arg6, zval* arg7, zval* arg8, zval* arg9 TSRMLS_DC)
{
	int result;
	zend_fcall_info fci;
	zval z_fname;
	zval *retval;
	HashTable *function_table;

	zval **params[9];

	params[0] = &arg1;
	params[1] = &arg2;
	params[2] = &arg3;
	params[3] = &arg4;
	params[4] = &arg5;
	params[5] = &arg6;
	params[6] = &arg7;
	params[7] = &arg8;
	params[8] = &arg9;

	fci.size = sizeof(fci);
	/*fci.function_table = NULL; will be read form zend_class_entry of object if needed */
	fci.object_ptr = object_pp ? *object_pp : NULL;
	fci.function_name = &z_fname;
	fci.retval_ptr_ptr = retval_ptr_ptr ? retval_ptr_ptr : &retval;
	fci.param_count = param_count;
	fci.params = params;
	fci.no_separation = 1;
	fci.symbol_table = NULL;

	if (!fn_proxy && !obj_ce) {
		/* no interest in caching and no information already present that is
		* needed later inside zend_call_function. */
		ZVAL_STRINGL(&z_fname, function_name, function_name_len, 0);
		fci.function_table = !object_pp ? EG(function_table) : NULL;
		result = zend_call_function(&fci, NULL TSRMLS_CC);
	} else {
		zend_fcall_info_cache fcic;
		fcic.initialized = 1;
		if (!obj_ce) {
			obj_ce = object_pp ? Z_OBJCE_PP(object_pp) : NULL;
		}
		if (obj_ce) {
			function_table = &obj_ce->function_table;
		} else {
			function_table = EG(function_table);
		}
		if (!fn_proxy || !*fn_proxy) {
			if (zend_hash_find(function_table, function_name, function_name_len+1, (void **) &fcic.function_handler) == FAILURE) {
				/* error at c-level */
				zend_error(E_CORE_ERROR, "Couldn't find implementation for method %s%s%s", obj_ce ? obj_ce->name : "", obj_ce ? "::" : "", function_name);
			}
			if (fn_proxy) {
				*fn_proxy = fcic.function_handler;
			}
		} else {
			fcic.function_handler = *fn_proxy;
		}
		fcic.calling_scope = obj_ce;
		if (object_pp) {
			fcic.called_scope = Z_OBJCE_PP(object_pp);
		} else if (obj_ce &&
			!(EG(called_scope) &&
			instanceof_function(EG(called_scope), obj_ce TSRMLS_CC))) {
			fcic.called_scope = obj_ce;
		} else {
			fcic.called_scope = EG(called_scope);
		}
		fcic.object_ptr = object_pp ? *object_pp : NULL;
		result = zend_call_function(&fci, &fcic TSRMLS_CC);
	}
	if (result == FAILURE) {
		/* error at c-level */
		if (!obj_ce) {
			obj_ce = object_pp ? Z_OBJCE_PP(object_pp) : NULL;
		}
		if (!EG(exception)) {
			zend_error(E_CORE_ERROR, "Couldn't execute method %s%s%s", obj_ce ? obj_ce->name : "", obj_ce ? "::" : "", function_name);
		}
	}
	if (!retval_ptr_ptr) {
		if (retval) {
			zval_ptr_dtor(&retval);
		}
		return NULL;
	}
	return *retval_ptr_ptr;
}
/* }}} */


/* {{{ */
/*
	Our default implementation for MySQLndUhConnection::query().
	It actually looks pretty stupid because it does nothing but
	call the original mysqlnd function handler in a super complicated
	way and exposing the internal mysqlnd connection to user land
	which is kind of a no go. However, its been the easiest way
	I could think of to allow users to write pre- and post hooks
	like this:

	class my_proxy extends MySQLndUhConnection {
	  function query($res, $query) {
	     print "pre hook goes here\n";
		 $ret = parent::query($res, $query);
		 print "post hook goes here\n";
		 return $ret;
	  }
	}
*/
PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, query)
{
	char *query_string;
	unsigned int query_string_len;
	zval *mysqlnd_rsrc;
	MYSQLND *conn;

	if (!MYSQLND_UH_G(enabled)) {
		php_error_docref(NULL TSRMLS_CC, E_WARNING, MYSLQND_UH_WARNING_CLASS_PLUGIN_DISABLED);
		RETURN_FALSE;
	}

	/* its ugly to tunnel the mysqlnd connection through the user land but we need it for calling the original mysqlnd functions */
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &mysqlnd_rsrc, &query_string, &query_string_len) == FAILURE) {
		RETURN_NULL();
	}
	ZEND_FETCH_RESOURCE(conn, MYSQLND*, &mysqlnd_rsrc, -1, MYSQLND_UH_RES_MYSQLND_NAME, le_mysqlnd_uh_mysqlnd);

	if (PASS == org_mysqlnd_conn_methods.query(conn, query_string, query_string_len TSRMLS_CC)) {
		RETVAL_TRUE;
	} else {
		RETVAL_FALSE;
	}
}
/* }}} */

#define CHECK_ENABLED() \
	if (!MYSQLND_UH_G(enabled)) { \
		php_error_docref(NULL TSRMLS_CC, E_WARNING, MYSLQND_UH_WARNING_CLASS_PLUGIN_DISABLED); \
		RETURN_FALSE; \
	}

#define PARSE_METHOD_SINGLE_PARAM_CONN(zv_rsrc, conn) \
	CHECK_ENABLED(); \
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zv_rsrc) == FAILURE) { \
		RETURN_NULL(); \
	} \
	ZEND_FETCH_RESOURCE(conn, MYSQLND*, &zv_rsrc, -1, MYSQLND_UH_RES_MYSQLND_NAME, le_mysqlnd_uh_mysqlnd);

/* {{{ */
PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, init)
{
	zval *mysqlnd_rsrc;
	MYSQLND *conn;

	PARSE_METHOD_SINGLE_PARAM_CONN(mysqlnd_rsrc, conn);
	org_mysqlnd_conn_methods.init(conn TSRMLS_CC);

	/* not needed by mysqlnd - userland only and not used */
	RETURN_TRUE;
}
/* }}} */


/* {{{ */
PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, connect)
{
	const char *host = NULL, *user = NULL, *passwd = NULL, *db = NULL, *socket = NULL;
	int host_len = 0, user_len = 0, passwd_len = 0, db_len = 0, socket_len = 0;
	long port = 0, mysql_flags = 0;
	zval* mysqlnd_rsrc;
	MYSQLND *conn;

	CHECK_ENABLED();
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsssslsl", &mysqlnd_rsrc,
		&host, &host_len, &user, &user_len, &passwd, &passwd_len,
		&db, &db_len, &port, &socket, &socket_len, &mysql_flags) == FAILURE) {
		RETURN_NULL();
	}
	ZEND_FETCH_RESOURCE(conn, MYSQLND*, &mysqlnd_rsrc, -1, MYSQLND_UH_RES_MYSQLND_NAME, le_mysqlnd_uh_mysqlnd);

	if (PASS == org_mysqlnd_conn_methods.connect(
		conn, host, user, passwd, passwd_len, db, db_len,
		port, socket, mysql_flags TSRMLS_CC)) {
		RETVAL_TRUE;
	} else {
		RETVAL_FALSE;
	}
}
/* }}} */


/* {{{ */
PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, escapeString)
{
	char *escapestr, *newstr;
	int escapestr_len;
	ulong newstr_len;
	zval* mysqlnd_rsrc;
	MYSQLND *conn;

	CHECK_ENABLED();
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &mysqlnd_rsrc, &escapestr, &escapestr_len) == FAILURE) {
		RETURN_NULL();
	}
	ZEND_FETCH_RESOURCE(conn, MYSQLND*, &mysqlnd_rsrc, -1, MYSQLND_UH_RES_MYSQLND_NAME, le_mysqlnd_uh_mysqlnd);

	newstr = safe_emalloc(2, escapestr_len, 1);
	newstr_len = org_mysqlnd_conn_methods.escape_string(conn, newstr, escapestr, escapestr_len TSRMLS_CC);
	newstr = erealloc(newstr, newstr_len + 1);

	RETURN_STRINGL(newstr, newstr_len, 0);
}
/* }}} */


/* {{{ */
PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, setCharset)
{
	char *charset;
	int charset_len;
	zval* mysqlnd_rsrc;
	MYSQLND *conn;

	CHECK_ENABLED();
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &mysqlnd_rsrc, &charset, &charset_len) == FAILURE) {
		RETURN_NULL();
	}
	ZEND_FETCH_RESOURCE(conn, MYSQLND*, &mysqlnd_rsrc, -1, MYSQLND_UH_RES_MYSQLND_NAME, le_mysqlnd_uh_mysqlnd);

	if (PASS == org_mysqlnd_conn_methods.set_charset(conn, charset TSRMLS_CC)) {
		RETVAL_TRUE;
	} else {
		RETVAL_FALSE;
	}
}
/* }}} */


/* {{{ */
PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, sendQuery)
{
	char *query;
	int query_len;
	zval* mysqlnd_rsrc;
	MYSQLND *conn;

	CHECK_ENABLED();
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &mysqlnd_rsrc, &query, &query_len) == FAILURE) {
		RETURN_NULL();
	}
	ZEND_FETCH_RESOURCE(conn, MYSQLND*, &mysqlnd_rsrc, -1, MYSQLND_UH_RES_MYSQLND_NAME, le_mysqlnd_uh_mysqlnd);

	if (PASS == org_mysqlnd_conn_methods.send_query(conn, query, query_len TSRMLS_CC)) {
		RETVAL_TRUE;
	} else {
		RETVAL_FALSE;
	}
}
/* }}} */

/* Its getting boring and becoming cut & paste - lets use the preprocessor */
#define CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_BOOL(mysqlnd_method_name, userland_method_name, true_value, conn_cast) \
	PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, userland_method_name) \
	{ \
		zval* mysqlnd_rsrc; \
		MYSQLND *conn; \
		\
		PARSE_METHOD_SINGLE_PARAM_CONN(mysqlnd_rsrc, conn); \
		\
		if (true_value == org_mysqlnd_conn_methods.mysqlnd_method_name((conn_cast)conn TSRMLS_CC)) { \
			RETVAL_TRUE; \
		} else { \
			RETVAL_FALSE; \
		} \
	}

#define CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_LONG(mysqlnd_method_name, userland_method_name, conn_cast) \
	PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, userland_method_name) \
	{ \
		zval* mysqlnd_rsrc; \
		MYSQLND *conn; \
		\
		PARSE_METHOD_SINGLE_PARAM_CONN(mysqlnd_rsrc, conn); \
		\
		RETVAL_LONG((long)org_mysqlnd_conn_methods.mysqlnd_method_name((conn_cast)conn TSRMLS_CC)); \
	}

/* TODO - check if we can do some sort of range checking here */
#define CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_UINT(mysqlnd_method_name, userland_method_name, conn_cast) \
	CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_LONG(mysqlnd_method_name, userland_method_name, conn_cast)

#define CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_UINT64(mysqlnd_method_name, userland_method_name, conn_cast) \
	CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_LONG(mysqlnd_method_name, userland_method_name, conn_cast)

#define CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_ULONG(mysqlnd_method_name, userland_method_name, conn_cast) \
	CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_LONG(mysqlnd_method_name, userland_method_name, conn_cast)

#define CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_STR(mysqlnd_method_name, userland_method_name, conn_cast) \
	PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, userland_method_name) \
	{ \
		zval* mysqlnd_rsrc; \
		MYSQLND *conn; \
                const char * tmp; \
		\
		PARSE_METHOD_SINGLE_PARAM_CONN(mysqlnd_rsrc, conn); \
		\
                tmp = org_mysqlnd_conn_methods.mysqlnd_method_name((conn_cast)conn TSRMLS_CC); \
		if (tmp) { \
			RETVAL_STRING(tmp, 1); \
		} else { \
			RETVAL_NULL(); \
		} \
	}


CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_BOOL(reap_query, reapQuery, PASS, MYSQLND *)

/* {{{ */
PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, useResult)
{
	zval* mysqlnd_rsrc;
	MYSQLND *conn;
	MYSQLND_RES *res;

	PARSE_METHOD_SINGLE_PARAM_CONN(mysqlnd_rsrc, conn);

	res = org_mysqlnd_conn_methods.use_result(conn TSRMLS_CC);
	ZEND_REGISTER_RESOURCE(return_value, (void *)res, le_mysqlnd_uh_mysqlnd_res);
}
/* }}} */


/* {{{ */
PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, storeResult)
{
	zval* mysqlnd_rsrc;
	MYSQLND *conn;
	MYSQLND_RES *res;

	PARSE_METHOD_SINGLE_PARAM_CONN(mysqlnd_rsrc, conn);

	res = org_mysqlnd_conn_methods.store_result(conn TSRMLS_CC);
	ZEND_REGISTER_RESOURCE(return_value, (void *)res, le_mysqlnd_uh_mysqlnd_res);
}
/* }}} */

CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_BOOL(next_result, nextResult, PASS, MYSQLND * const)
CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_BOOL(more_results, moreResults, TRUE, const MYSQLND * const)

/* {{{ */
PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, stmtInit)
{
	zval* mysqlnd_rsrc;
	MYSQLND *conn;
	MYSQLND_STMT *res;

	PARSE_METHOD_SINGLE_PARAM_CONN(mysqlnd_rsrc, conn);

	res = org_mysqlnd_conn_methods.stmt_init(conn TSRMLS_CC);
	ZEND_REGISTER_RESOURCE(return_value, (void *)res, le_mysqlnd_uh_mysqlnd_stmt);
}
/* }}} */


/* {{{ */
PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, shutdownServer)
{
	zval* mysqlnd_rsrc;
	MYSQLND *conn;
	long level;

	CHECK_ENABLED();
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &mysqlnd_rsrc, &level) == FAILURE) {
		RETURN_NULL();
	}
	ZEND_FETCH_RESOURCE(conn, MYSQLND*, &mysqlnd_rsrc, -1, MYSQLND_UH_RES_MYSQLND_NAME, le_mysqlnd_uh_mysqlnd);

	if (TRUE == org_mysqlnd_conn_methods.shutdown_server(conn, level TSRMLS_CC)) {
		RETVAL_TRUE;
	} else {
		RETVAL_FALSE;
	}
}
/* }}} */

/* {{{ */
PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, refreshServer)
{
	zval* mysqlnd_rsrc;
	MYSQLND *conn;
	long options;

	CHECK_ENABLED();
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &mysqlnd_rsrc, &options) == FAILURE) {
		RETURN_NULL();
	}
	ZEND_FETCH_RESOURCE(conn, MYSQLND*, &mysqlnd_rsrc, -1, MYSQLND_UH_RES_MYSQLND_NAME, le_mysqlnd_uh_mysqlnd);

	if (TRUE == org_mysqlnd_conn_methods.refresh_server(conn, (uint8_t)options TSRMLS_CC)) {
		RETVAL_TRUE;
	} else {
		RETVAL_FALSE;
	}
}
/* }}} */

CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_BOOL(ping, ping, PASS, MYSQLND * const)

/* {{{ */
PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, killConnection)
{
	zval* mysqlnd_rsrc;
	MYSQLND *conn;
	long pid;

	CHECK_ENABLED();
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &mysqlnd_rsrc, &pid) == FAILURE) {
		RETURN_NULL();
	}
	ZEND_FETCH_RESOURCE(conn, MYSQLND*, &mysqlnd_rsrc, -1, MYSQLND_UH_RES_MYSQLND_NAME, le_mysqlnd_uh_mysqlnd);

	if (PASS == org_mysqlnd_conn_methods.kill_connection(conn, (unsigned int)pid TSRMLS_CC)) {
		RETVAL_TRUE;
	} else {
		RETVAL_FALSE;
	}
}
/* }}} */


/* {{{ */
PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, selectDb)
{
	zval* mysqlnd_rsrc;
	MYSQLND *conn;
	char *db;
	unsigned int db_len;

	CHECK_ENABLED();
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &mysqlnd_rsrc, &db, &db_len) == FAILURE) {
		RETURN_NULL();
	}
	ZEND_FETCH_RESOURCE(conn, MYSQLND*, &mysqlnd_rsrc, -1, MYSQLND_UH_RES_MYSQLND_NAME, le_mysqlnd_uh_mysqlnd);

	if (PASS == org_mysqlnd_conn_methods.select_db(conn, db, db_len TSRMLS_CC)) {
		RETVAL_TRUE;
	} else {
		RETVAL_FALSE;
	}
}
/* }}} */


CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_BOOL(server_dump_debug_information, serverDumpDebugInformation, PASS, MYSQLND * const)


/* {{{ */
PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, changeUser)
{
	zval* mysqlnd_rsrc;
	MYSQLND *conn;
	char *user, *passwd, *db;
	unsigned int user_len, passwd_len, db_len;
	zend_bool silent;

	CHECK_ENABLED();
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsssb", &mysqlnd_rsrc, &user, &user_len, &passwd, &passwd_len, &db, &db_len, &silent) == FAILURE) {
		RETURN_NULL();
	}
	ZEND_FETCH_RESOURCE(conn, MYSQLND*, &mysqlnd_rsrc, -1, MYSQLND_UH_RES_MYSQLND_NAME, le_mysqlnd_uh_mysqlnd);

	if (PASS == org_mysqlnd_conn_methods.change_user(conn, user, passwd, db, silent TSRMLS_CC)) {
		RETVAL_TRUE;
	} else {
		RETVAL_FALSE;
	}
}
/* }}} */

CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_UINT(get_error_no, getErrorNumber, const MYSQLND * const)
CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_STR(get_error_str, getErrorString, const MYSQLND * const)
CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_STR(get_sqlstate, getSqlstate, const MYSQLND * const)
CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_UINT64(get_thread_id, getThreadId, const MYSQLND * const)

/* {{{ */
PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, getStatistics)
{
	zval* mysqlnd_rsrc;
	MYSQLND *conn;

	CHECK_ENABLED();
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &mysqlnd_rsrc) == FAILURE) {
		RETURN_NULL();
	}
	ZEND_FETCH_RESOURCE(conn, MYSQLND*, &mysqlnd_rsrc, -1, MYSQLND_UH_RES_MYSQLND_NAME, le_mysqlnd_uh_mysqlnd);

	org_mysqlnd_conn_methods.get_statistics(conn, return_value TSRMLS_CC ZEND_FILE_LINE_CC);
}
/* }}} */

CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_ULONG(get_server_version, getServerVersion, const MYSQLND * const)
CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_STR(get_server_information, getServerInformation, const MYSQLND * const)

/* {{{ */
PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, getServerStatistics)
{
	char * stat = NULL;
	unsigned int stat_len = 0;
	zval* mysqlnd_rsrc;
	MYSQLND *conn;

	CHECK_ENABLED();
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &mysqlnd_rsrc) == FAILURE) {
		RETURN_NULL();
	}
	ZEND_FETCH_RESOURCE(conn, MYSQLND*, &mysqlnd_rsrc, -1, MYSQLND_UH_RES_MYSQLND_NAME, le_mysqlnd_uh_mysqlnd);

	org_mysqlnd_conn_methods.get_server_statistics(conn, &stat, &stat_len TSRMLS_CC);
	RETURN_STRINGL(stat, stat_len, 0);
}
/* }}} */

CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_STR(get_host_information, getHostInformation, const MYSQLND * const)
CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_UINT(get_protocol_information, getProtocolInformation, const MYSQLND * const)
CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_STR(get_last_message, getLastMessage, const MYSQLND * const)
CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_STR(charset_name, charsetName, const MYSQLND * const)

/* {{{ */
PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, listFields)
{
	zval* mysqlnd_rsrc;
	MYSQLND *conn;
	MYSQLND_RES *res;
	char *table, *achtung_wild;
	unsigned int table_len, achtung_wild_len;

	CHECK_ENABLED();
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss", &mysqlnd_rsrc, &table, &table_len, &achtung_wild, &achtung_wild_len) == FAILURE) {
		RETURN_NULL();
	}
	ZEND_FETCH_RESOURCE(conn, MYSQLND*, &mysqlnd_rsrc, -1, MYSQLND_UH_RES_MYSQLND_NAME, le_mysqlnd_uh_mysqlnd);

	res = org_mysqlnd_conn_methods.list_fields(conn, table, achtung_wild TSRMLS_CC);
	ZEND_REGISTER_RESOURCE(return_value, (void *)res, le_mysqlnd_uh_mysqlnd_res);
}
/* }}} */


/* {{{ */
PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, listMethod)
{
	zval* mysqlnd_rsrc;
	MYSQLND *conn;
	MYSQLND_RES *res;
	char *query, *achtung_wild, *par1;
	unsigned int query_len, achtung_wild_len, par1_len;

	CHECK_ENABLED();
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsss", &mysqlnd_rsrc, &query, &query_len, &achtung_wild, &achtung_wild_len, &par1, &par1_len) == FAILURE) {
		RETURN_NULL();
	}
	ZEND_FETCH_RESOURCE(conn, MYSQLND*, &mysqlnd_rsrc, -1, MYSQLND_UH_RES_MYSQLND_NAME, le_mysqlnd_uh_mysqlnd);

	res = org_mysqlnd_conn_methods.list_method(conn, query, achtung_wild, par1 TSRMLS_CC);
	ZEND_REGISTER_RESOURCE(return_value, (void *)res, le_mysqlnd_uh_mysqlnd_res);
}
/* }}} */


CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_UINT64(get_last_insert_id, getLastInsertId, const MYSQLND * const)
CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_UINT64(get_affected_rows, getAffectedRows, const MYSQLND * const)
CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_UINT(get_warning_count, getWarningCount, const MYSQLND * const)
CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_UINT(get_field_count, getFieldCount, const MYSQLND * const)


/* {{{ */
PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, setServerOption)
{
	zval* mysqlnd_rsrc;
	MYSQLND *conn;
	long option;

	CHECK_ENABLED();
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &mysqlnd_rsrc, &option) == FAILURE) {
		RETURN_NULL();
	}
	ZEND_FETCH_RESOURCE(conn, MYSQLND*, &mysqlnd_rsrc, -1, MYSQLND_UH_RES_MYSQLND_NAME, le_mysqlnd_uh_mysqlnd);

	if (PASS == org_mysqlnd_conn_methods.set_server_option(conn, option TSRMLS_CC)) {
		RETVAL_TRUE;
	} else {
		RETVAL_FALSE;
	}
}
/* }}} */


/* {{{ */
PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, setClientOption)
{
	zval* mysqlnd_rsrc;
	MYSQLND *conn;
	long option;
	zval* zv_value;
	char *value = NULL;
	enum_func_status ret;

	CHECK_ENABLED();
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlz", &mysqlnd_rsrc, &option, &zv_value) == FAILURE) {
		RETURN_NULL();
	}
	ZEND_FETCH_RESOURCE(conn, MYSQLND*, &mysqlnd_rsrc, -1, MYSQLND_UH_RES_MYSQLND_NAME, le_mysqlnd_uh_mysqlnd);

	switch (Z_TYPE_P(zv_value)) {
		case IS_STRING:
			value = Z_STRVAL_P(zv_value);
			ret = org_mysqlnd_conn_methods.set_client_option(conn, option, value TSRMLS_CC);
			break;

		case IS_LONG:
			value = ecalloc(1, 256);
			snprintf(value, 256, "%ld", Z_LVAL_P(zv_value));
			ret = org_mysqlnd_conn_methods.set_client_option(conn, option, value TSRMLS_CC);
			efree(value);
			break;

		case IS_BOOL:
			value = (Z_BVAL_P(zv_value)) ? "1" : "0";
			ret = org_mysqlnd_conn_methods.set_client_option(conn, option, value TSRMLS_CC);
			break;

		case IS_NULL:
			value = NULL;
			ret = org_mysqlnd_conn_methods.set_client_option(conn, option, value TSRMLS_CC);
			break;

		default:
			php_error_docref(NULL TSRMLS_CC, E_ERROR, MYSQLND_UH_ERROR_PREFIX " Option value must by of type integer, double, string, boolean or be NULL ");
			ret = FAIL;
			break;
	}

	if (PASS == ret) {
		RETVAL_TRUE;
	} else {
		RETVAL_FALSE;
	}
}
/* }}} */


/* {{{ */
PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, close)
{
	zval* mysqlnd_rsrc;
	MYSQLND *conn;
	long close_type;

	CHECK_ENABLED();
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &mysqlnd_rsrc, &close_type) == FAILURE) {
		RETURN_NULL();
	}
	ZEND_FETCH_RESOURCE(conn, MYSQLND*, &mysqlnd_rsrc, -1, MYSQLND_UH_RES_MYSQLND_NAME, le_mysqlnd_uh_mysqlnd);

	if (PASS == org_mysqlnd_conn_methods.close((MYSQLND *)conn, (enum_connection_close_type)close_type TSRMLS_CC)) {
		RETVAL_TRUE;
	} else {
		RETVAL_FALSE;
	}
}
/* }}} */


/* {{{ */
PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, queryReadResultsetHeader)
{
	zval* mysqlnd_rsrc;
	zval* zv_stmt;
	MYSQLND *conn;
	MYSQLND_STMT *stmt;

	CHECK_ENABLED();
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz", &mysqlnd_rsrc, &zv_stmt) == FAILURE) {
		RETURN_NULL();
	}
	ZEND_FETCH_RESOURCE(conn, MYSQLND*, &mysqlnd_rsrc, -1, MYSQLND_UH_RES_MYSQLND_NAME, le_mysqlnd_uh_mysqlnd);
	if (Z_TYPE_P(zv_stmt) == IS_RESOURCE) {
		ZEND_FETCH_RESOURCE(stmt, MYSQLND_STMT*, &zv_stmt, -1, MYSQLND_UH_RES_MYSQLND_STMT_NAME, le_mysqlnd_uh_mysqlnd_stmt);
	} else if (Z_TYPE_P(zv_stmt) == IS_NULL) {
		stmt = NULL;
	} else {
		php_error_docref(NULL TSRMLS_CC, E_WARNING, MYSQLND_UH_ERROR_PREFIX " The second parameter must be either a resource of type " MYSQLND_UH_RES_MYSQLND_STMT_NAME " or NULL");
		RETURN_NULL();
	}

	if (PASS == org_mysqlnd_conn_methods.query_read_result_set_header(conn, stmt TSRMLS_CC)) {
		RETVAL_TRUE;
	} else {
		RETVAL_FALSE;
	}
}
/* }}} */


/* {{{ */
PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, simpleCommand)
{
	zval* mysqlnd_rsrc;
	MYSQLND *conn;
	char * arg;
	int arg_len = 0;
	long command, ok_packet;
	zend_bool silent, ignore_upsert_status;

	CHECK_ENABLED();
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlslbb", &mysqlnd_rsrc, &command, &arg, &arg_len, &ok_packet, &silent, &ignore_upsert_status) == FAILURE) {
		RETURN_NULL();
	}
	ZEND_FETCH_RESOURCE(conn, MYSQLND*, &mysqlnd_rsrc, -1, MYSQLND_UH_RES_MYSQLND_NAME, le_mysqlnd_uh_mysqlnd);

	if (PASS == org_mysqlnd_conn_methods.simple_command(conn, command,
		arg, arg_len, ok_packet, silent, ignore_upsert_status TSRMLS_CC)) {
		RETVAL_TRUE;
	} else {
		RETVAL_FALSE;
	}
}
/* }}} */

/* {{{ */
PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, simpleCommandHandleResponse)
{
	zval* mysqlnd_rsrc;
	MYSQLND *conn;
	long command, ok_packet;
	zend_bool silent, ignore_upsert_status;

	CHECK_ENABLED();
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlblb", &mysqlnd_rsrc,  &ok_packet, &silent, &command, &ignore_upsert_status) == FAILURE) {
		RETURN_NULL();
	}
	ZEND_FETCH_RESOURCE(conn, MYSQLND*, &mysqlnd_rsrc, -1, MYSQLND_UH_RES_MYSQLND_NAME, le_mysqlnd_uh_mysqlnd);

	if (PASS == org_mysqlnd_conn_methods.simple_command_handle_response(conn, ok_packet, silent, command, ignore_upsert_status TSRMLS_CC)) {
		RETVAL_TRUE;
	} else {
		RETVAL_FALSE;
	}
}
/* }}} */


CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_BOOL(restart_psession, restartPSession, PASS, MYSQLND *)
CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_BOOL(end_psession, endPSession, PASS, MYSQLND *)
CLASS_CONN_PHP_METHOD_ONE_ARG_CONN_RET_BOOL(send_close, sendClose, PASS, MYSQLND *)

/* {{{ */
PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, sslSet)
{
	zval* mysqlnd_rsrc;
	MYSQLND *conn;
	const char *key, *cert, *ca, *capath, *cipher;
	unsigned int key_len, cert_len, ca_len, capath_len, cipher_len;

	CHECK_ENABLED();
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsssss", &mysqlnd_rsrc,  &key, &key_len,
		&cert, &cert_len, &ca, &ca_len, &capath, &capath_len, &cipher, &cipher_len) == FAILURE) {
		RETURN_NULL();
	}
	ZEND_FETCH_RESOURCE(conn, MYSQLND*, &mysqlnd_rsrc, -1, MYSQLND_UH_RES_MYSQLND_NAME, le_mysqlnd_uh_mysqlnd);

	org_mysqlnd_conn_methods.ssl_set(conn, key, cert, ca, capath, cipher TSRMLS_CC);

/*  FIXME: mysqlnd should return PASS/FAIL but doesn't. This is fixed in recent php
	builds 

 	if (PASS == org_mysqlnd_conn_methods.ssl_set(conn, key, cert, ca, capath, cipher TSRMLS_CC)) {
		RETVAL_TRUE;
	} else {
		RETVAL_FALSE;
	}*/
}
/* }}} */

/* {{{ */
PHP_METHOD(MYSQLND_UH_CLASS_CONNECTION_NAME, __construct)
{
	if (!MYSQLND_UH_G(enabled)) {
		php_error_docref(NULL TSRMLS_CC, E_WARNING, MYSLQND_UH_WARNING_CLASS_PLUGIN_DISABLED);
		RETURN_FALSE;
	}
}
/* }}} */

/* Additional argument info for Zend - may it be used for helpful dev tips... */
ZEND_BEGIN_ARG_INFO(query_arginfo, 0)
	ZEND_ARG_INFO(0, MYSQLND_UH_RES_MYSQLND_NAME)
	ZEND_ARG_INFO(0, "query_string")
ZEND_END_ARG_INFO()

/* Well, you got the idea, let's use some preprocessor magic */
#define METHOD_ARG_INFO_BEGIN_W_CONN(method) \
	ZEND_BEGIN_ARG_INFO(method, 0) \
		ZEND_ARG_INFO(0, MYSQLND_UH_RES_MYSQLND_NAME)

#define METHOD_ARG_INFO_END() \
	ZEND_END_ARG_INFO()

#define METHOD_ARG_INFO_CONN_ONLY_ARG(name) \
	METHOD_ARG_INFO_BEGIN_W_CONN(name) \
	METHOD_ARG_INFO_END()

#define METHOD_ARG_INFO_CONN_TWO_ARGS(name, by_ref_arg2, name_arg2) \
	METHOD_ARG_INFO_BEGIN_W_CONN(name) \
		ZEND_ARG_INFO(by_ref_arg2, name_arg2) \
	METHOD_ARG_INFO_END()

METHOD_ARG_INFO_CONN_ONLY_ARG(init_arginfo)

METHOD_ARG_INFO_BEGIN_W_CONN(connect_arginfo)
	ZEND_ARG_INFO(0, "host")
	ZEND_ARG_INFO(0, "user")
	ZEND_ARG_INFO(0, "password")
	ZEND_ARG_INFO(0, "database")
	ZEND_ARG_INFO(0, "port")
	ZEND_ARG_INFO(0, "socket")
	ZEND_ARG_INFO(0, "mysql_flags")
METHOD_ARG_INFO_END()

METHOD_ARG_INFO_CONN_TWO_ARGS(escapeString_arginfo, 0, "escape_string")
METHOD_ARG_INFO_CONN_TWO_ARGS(setCharset_arginfo, 0, "charset")
METHOD_ARG_INFO_CONN_TWO_ARGS(sendQuery_arginfo, 0, "query")
METHOD_ARG_INFO_CONN_ONLY_ARG(reapQuery_arginfo)
METHOD_ARG_INFO_CONN_ONLY_ARG(useResult_arginfo)
METHOD_ARG_INFO_CONN_ONLY_ARG(storeResult_arginfo)
METHOD_ARG_INFO_CONN_ONLY_ARG(nextResult_arginfo)
METHOD_ARG_INFO_CONN_ONLY_ARG(moreResults_arginfo)
METHOD_ARG_INFO_CONN_ONLY_ARG(stmtInit_arginfo)
METHOD_ARG_INFO_CONN_TWO_ARGS(shutdownServer_arginfo, 0, "level")
METHOD_ARG_INFO_CONN_TWO_ARGS(refreshServer_arginfo, 0, "options")
METHOD_ARG_INFO_CONN_ONLY_ARG(ping_arginfo)
METHOD_ARG_INFO_CONN_TWO_ARGS(killConnection_arginfo, 0, "pid")
METHOD_ARG_INFO_CONN_TWO_ARGS(selectDb_arginfo, 0, "database")
METHOD_ARG_INFO_CONN_ONLY_ARG(serverDumpDebugInformation_arginfo)

METHOD_ARG_INFO_BEGIN_W_CONN(changeUser_arginfo)
	ZEND_ARG_INFO(0, "user")
	ZEND_ARG_INFO(0, "password")
	ZEND_ARG_INFO(0, "database")
	ZEND_ARG_INFO(0, "silent")
METHOD_ARG_INFO_END()

METHOD_ARG_INFO_CONN_ONLY_ARG(getErrorNumber_arginfo)
METHOD_ARG_INFO_CONN_ONLY_ARG(getErrorString_arginfo)
METHOD_ARG_INFO_CONN_ONLY_ARG(getSqlstate_arginfo)
METHOD_ARG_INFO_CONN_ONLY_ARG(getThreadId_arginfo)
METHOD_ARG_INFO_CONN_ONLY_ARG(getStatistics_arginfo)
METHOD_ARG_INFO_CONN_ONLY_ARG(getServerVersion_arginfo)
METHOD_ARG_INFO_CONN_ONLY_ARG(getServerInformation_arginfo)
METHOD_ARG_INFO_CONN_ONLY_ARG(getServerStatistics_arginfo)
METHOD_ARG_INFO_CONN_ONLY_ARG(getHostInformation_arginfo)
METHOD_ARG_INFO_CONN_ONLY_ARG(getProtocolInformation_arginfo)
METHOD_ARG_INFO_CONN_ONLY_ARG(getLastMessage_arginfo)
METHOD_ARG_INFO_CONN_ONLY_ARG(charsetName_arginfo)

METHOD_ARG_INFO_BEGIN_W_CONN(listFields_arginfo)
	ZEND_ARG_INFO(0, "table")
	ZEND_ARG_INFO(0, "achtung_wild")
METHOD_ARG_INFO_END()

METHOD_ARG_INFO_BEGIN_W_CONN(listMethod_arginfo)
	ZEND_ARG_INFO(0, "query")
	ZEND_ARG_INFO(0, "achtung_wild")
	ZEND_ARG_INFO(0, "par1")
METHOD_ARG_INFO_END()

METHOD_ARG_INFO_CONN_ONLY_ARG(getLastInsertId_arginfo)
METHOD_ARG_INFO_CONN_ONLY_ARG(getAffectedRows_arginfo)
METHOD_ARG_INFO_CONN_ONLY_ARG(getWarningCount_arginfo)
METHOD_ARG_INFO_CONN_ONLY_ARG(getFieldCount_arginfo)

METHOD_ARG_INFO_BEGIN_W_CONN(setServerOption_arginfo)
	ZEND_ARG_INFO(0, "option")
METHOD_ARG_INFO_END()

METHOD_ARG_INFO_BEGIN_W_CONN(setClientOption_arginfo)
	ZEND_ARG_INFO(0, "option")
	ZEND_ARG_INFO(0, "value")
METHOD_ARG_INFO_END()

METHOD_ARG_INFO_BEGIN_W_CONN(close_arginfo)
	ZEND_ARG_INFO(0, "close_type")
METHOD_ARG_INFO_END()

METHOD_ARG_INFO_BEGIN_W_CONN(queryReadResultsetHeader_arginfo)
	ZEND_ARG_INFO(0, "mysqlnd_stmt")
METHOD_ARG_INFO_END()

METHOD_ARG_INFO_BEGIN_W_CONN(simpleCommand_arginfo)
	ZEND_ARG_INFO(0, "command")
	ZEND_ARG_INFO(0, "arg")
	ZEND_ARG_INFO(0, "ok_packet")
	ZEND_ARG_INFO(0, "silent")
	ZEND_ARG_INFO(0, "ignore_upsert_status")
METHOD_ARG_INFO_END()

METHOD_ARG_INFO_BEGIN_W_CONN(simpleCommandHandleResponse_arginfo)
	ZEND_ARG_INFO(0, "ok_packet")
	ZEND_ARG_INFO(0, "silent")
	ZEND_ARG_INFO(0, "command")
	ZEND_ARG_INFO(0, "ignore_upsert_status")
METHOD_ARG_INFO_END()

METHOD_ARG_INFO_CONN_ONLY_ARG(restartPSession_arginfo)
METHOD_ARG_INFO_CONN_ONLY_ARG(endPSession_arginfo)
METHOD_ARG_INFO_CONN_ONLY_ARG(sendClose_arginfo)

METHOD_ARG_INFO_BEGIN_W_CONN(sslSet_arginfo)
	ZEND_ARG_INFO(0, "key")
	ZEND_ARG_INFO(0, "cert")
	ZEND_ARG_INFO(0, "ca")
	ZEND_ARG_INFO(0, "capath")
	ZEND_ARG_INFO(0, "cipher")
METHOD_ARG_INFO_END()

static function_entry php_mysqlnd_uh_class_connection_functions[] = {
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, query, query_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, init, init_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, connect, connect_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, escapeString, escapeString_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, setCharset, setCharset_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, sendQuery, sendQuery_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, reapQuery, reapQuery_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, useResult, useResult_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, storeResult, storeResult_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, nextResult, nextResult_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, moreResults, moreResults_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, stmtInit, stmtInit_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, shutdownServer, shutdownServer_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, refreshServer, refreshServer_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, ping, ping_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, killConnection, killConnection_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, selectDb, selectDb_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, serverDumpDebugInformation, serverDumpDebugInformation_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, changeUser, changeUser_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, getErrorNumber, getErrorNumber_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, getErrorString, getErrorString_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, getSqlstate, getSqlstate_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, getThreadId, getThreadId_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, getStatistics, getStatistics_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, getServerVersion, getServerVersion_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, getServerInformation, getServerInformation_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, getServerStatistics, getServerStatistics_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, getHostInformation, getHostInformation_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, getProtocolInformation, getProtocolInformation_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, getLastMessage, getLastMessage_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, charsetName, charsetName_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, listFields, listFields_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, listMethod, listMethod_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, getLastInsertId, getLastInsertId_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, getAffectedRows, getAffectedRows_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, getWarningCount, getWarningCount_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, getFieldCount, getFieldCount_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, setServerOption, setServerOption_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, setClientOption, setClientOption_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, close, close_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, queryReadResultsetHeader, queryReadResultsetHeader_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, simpleCommand, simpleCommand_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, simpleCommandHandleResponse, simpleCommandHandleResponse_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, restartPSession, restartPSession_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, endPSession, endPSession_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, sendClose, sendClose_arginfo, ZEND_ACC_PUBLIC)
	PHP_ME(MYSQLND_UH_CLASS_CONNECTION_NAME, sslSet, sslSet_arginfo, ZEND_ACC_PUBLIC)
	{ NULL, NULL, NULL }
};

/* {{{ */
void mysqlnd_uh_minit_register_classes(TSRMLS_D)
{
	/* register the classes defined by the extension during MINIT */
	zend_class_entry ce;

	INIT_CLASS_ENTRY(ce, MYSQLND_UH_CLASS_CONNECTION_NAME, php_mysqlnd_uh_class_connection_functions);
	php_mysqlnd_uh_class_connection_entry = zend_register_internal_class(&ce TSRMLS_CC);
}
/* }}} */

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim600: noet sw=4 ts=4 fdm=marker
 * vim<600: noet sw=4 ts=4
 */
